package bblvolume

import (
	"errors"
	"fmt"
	"io"
	"time"
)

var (
	UnsupportedOperation = errors.New("unsupported operation")
)

type WalkFunc func(path string, meta ObjectInfo, err error) error

type NotifyFunc func(path string, event int, meta ObjectInfo, err error) error

type StorageStat struct {
	Export     string
	DevName    string
	TotalSpace uint64
	UsedSpace  uint64
	FreeSpace  uint64
}

type StorageSystem interface {
	UUID() string
	ClusterServer() []string
	ClusterPassphrase() string
	TransAddr() string
	Create(name string) (Object, error)
	Open(name string, flag int) (Object, error)
	Find(name string) (Object, error)
	Rename(from, to string) error
	Remove(name string) error
	Link(from, to string) error
	Copy(from, to string) error
	RemoveAll(path string) error
	Mkdirs(path string) error
	Exist(name string) bool
	Walk(path string, walkFn WalkFunc)
	Notify(path string, event int, notifyFn NotifyFunc) //订阅存储系统事件
	Stat(name string) (ObjectInfo, error)
	String() string
	StorageStat() *StorageStat
}

type ObjectInfo interface {
	Name() string
	LinkPath() string
	IsDir() bool
	IsLink() bool
	IsObject() bool
	Size() int64
	Endpoint() string //http://uuid:9933/xxx/xxx/xxx/xxx/xxx/xxx.vod
	CreateTime() time.Time
	AccessTime() time.Time
	ModTime() time.Time
}

type Object interface {
	Name() string
	Read(p []byte) (n int, err error)
	ReadAt(p []byte, off int64) (n int, err error)
	ReadFrom(r io.Reader) (n int64, err error)
	Write(p []byte) (n int, err error)
	WriteAt(p []byte, off int64) (n int, err error)
	WriteTo(w io.Writer) (n int64, err error)
	Seek(offset int64, whence int) (int64, error)
	Truncate(size int64) error
	Close() error
	Stat() (ObjectInfo, error)
}

var dbs = map[string]StorageSystem{}

func Register(s StorageSystem) {
	name := s.String()
	if _, ok := dbs[name]; ok {
		panic(fmt.Errorf("storage system %s is registered", name))
	}

	dbs[name] = s
}

func ListStorageSystem() []string {
	s := []string{}
	for k, _ := range dbs {
		s = append(s, k)
	}

	return s
}

func GetStorageSystem(name string) (StorageSystem, error) {
	if s, ok := dbs[name]; ok {
		return s, nil
	}
	return nil, fmt.Errorf("storage system %s is not registered", name)
}
